#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "uart_init.h"
#include "gpio_init.h"
#include "my_zw101.h"

typedef struct queue_uart
{
    uint8_t buffer[MY_ZW101_PACK_BUFF_LEN];
    uint16_t len;
} queue_uart_node;

static const char *TAG = "main";
static uart_init_node uart1_node = {};
static my_zw101_node zw101_node = {}; // zw101包
static gpio_init_node touch_pin = {}; // zw101活体感应
static gpio_init_node ctrl_pin = {};  // zw101模组电源控制
static gpio_init_node mag_pin = {};   // 锁控制
static QueueHandle_t xQueue = NULL;

/**
 * zw101驱动配置函数
 */
static void zw101_div(my_zw101_node *node)
{
    static const char *TAG = "main zw101";
    ESP_LOGI(TAG, "len = [%d]", node->pack_buffer_len);
    ESP_LOG_BUFFER_HEXDUMP(TAG, node->pack_buffer, node->pack_buffer_len, ESP_LOG_INFO);
    uart_write_bytes(uart1_node.uart_num, node->pack_buffer, node->pack_buffer_len);
    vTaskDelay(pdMS_TO_TICKS(200));
}

/**
 * 整体初始化和配置
 */
static void config_init(void)
{
    uart1_node.uart_num = UART_NUM_1;
    uart1_node.rate = 57600;
    uart1_node.rx_pin = 1;
    uart1_node.tx_pin = 0;
    uart1_node.buffer = 1024;
    uart_config_init(&uart1_node);

    touch_pin.pin = GPIO_NUM_2;
    touch_pin.status = 0;
    touch_pin.config.pin_bit_mask = 1 << touch_pin.pin;
    touch_pin.config.mode = GPIO_MODE_INPUT;
    touch_pin.config.pull_up_en = GPIO_PULLUP_DISABLE;
    touch_pin.config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    touch_pin.config.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&touch_pin.config);

    ctrl_pin.pin = GPIO_NUM_18;
    ctrl_pin.status = 0;
    ctrl_pin.config.pin_bit_mask = 1 << ctrl_pin.pin;
    ctrl_pin.config.mode = GPIO_MODE_OUTPUT;
    ctrl_pin.config.pull_up_en = GPIO_PULLUP_DISABLE;
    ctrl_pin.config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    ctrl_pin.config.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&ctrl_pin.config);

    mag_pin.pin = GPIO_NUM_19;
    mag_pin.status = 0;
    mag_pin.config.pin_bit_mask = 1 << mag_pin.pin;
    mag_pin.config.mode = GPIO_MODE_OUTPUT;
    mag_pin.config.pull_up_en = GPIO_PULLUP_DISABLE;
    mag_pin.config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    mag_pin.config.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&mag_pin.config);

    zw101_node.address = 0xffffffff;
    zw101_node.div_p = zw101_div;
}

/**
 * 串口接收任务
 */
static void uart1_read_task(void *arg)
{
    static const char *TAG = "main uart1 read";
    queue_uart_node *node = (queue_uart_node *)malloc(sizeof(queue_uart_node));
    assert(node);
    uint8_t *data = (uint8_t *)malloc(uart1_node.buffer * sizeof(uint8_t));
    assert(data);
    for (;;)
    {
        int len = uart_read_bytes(uart1_node.uart_num, data, (uart1_node.buffer - 1), pdMS_TO_TICKS(50));
        if (len)
        {
            ESP_LOGI(TAG, "len = [%d]", len);
            ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_INFO);
            node->len = len;
            if (node->len < MY_ZW101_PACK_BUFF_LEN)
            {
                memcpy((char *)node->buffer, (char *)data, node->len);
                xQueueSend(xQueue, node, (TickType_t)0);
            }
        }
    }
    free(node);
    free(data);
}

/**
 * 任务初始化
 */
static void task_init(void)
{
    xQueue = xQueueCreate(15, sizeof(queue_uart_node));
    xTaskCreate(uart1_read_task, "uart read", 2 * 1024, NULL, 3, NULL);
}

void app_main(void)
{
    static queue_uart_node node;

    config_init();
    task_init();

    // 开启电源
    ctrl_pin.status = 1;
    gpio_set_level(ctrl_pin.pin, ctrl_pin.status);
    vTaskDelay(pdMS_TO_TICKS(200));

    my_zw101_ps_check_sensor(&zw101_node);
    while (xQueueReceive(xQueue, &node, (TickType_t)0) == pdTRUE)
    {
        memcpy(zw101_node.pack_buffer, node.buffer, node.len);
        zw101_node.pack_buffer_len = node.len;
        uint16_t head, len;
        if (my_zw101_answer_check(&zw101_node, &head, &len) == 0)
        {
            ESP_LOGI(TAG, "answer check success");
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }

    my_zw101_ps_sleep(&zw101_node);
    while (xQueueReceive(xQueue, &node, (TickType_t)0) == pdTRUE)
    {
        memcpy(zw101_node.pack_buffer, node.buffer, node.len);
        zw101_node.pack_buffer_len = node.len;
        uint16_t head, len;
        if (my_zw101_answer_check(&zw101_node, &head, &len) == 0)
        {
            ESP_LOGI(TAG, "answer check success");
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
    // 关闭电源
    ctrl_pin.status = 0;
    gpio_set_level(ctrl_pin.pin, ctrl_pin.status);

    for (;;)
    {
        if (ctrl_pin.status == 0)
        {
            touch_pin.status = gpio_get_level(touch_pin.pin);
            if (touch_pin.status == 1)
            {
                ESP_LOGI(TAG, "pin status = [%d]", touch_pin.status);
                ctrl_pin.status = 1;
                gpio_set_level(ctrl_pin.pin, ctrl_pin.status); // 开启电源
                vTaskDelay(pdMS_TO_TICKS(100));
                my_zw101_ps_auto_identify(&zw101_node, 1, 0xffff, 0x0000); // 验证指纹
                uint8_t zw101_ps_auto_flag = 0;                            // 验证是否成功标识0为成功，1为失败
                while (xQueueReceive(xQueue, &node, (TickType_t)0) == pdTRUE)
                {
                    memcpy(zw101_node.pack_buffer, node.buffer, node.len);
                    zw101_node.pack_buffer_len = node.len;
                    uint16_t head, len;
                    if (my_zw101_answer_check(&zw101_node, &head, &len) == 0)
                    {
                        ESP_LOGI(TAG, "answer check read");
                        ESP_LOGI(TAG, "head = [%d]", head);
                        // 校验
                        if (zw101_node.pack_buffer[head] == 0x00)
                        {
                            // todo处理数据，可以增加身份显示功能和验证符合百分比信息
                            if (zw101_node.pack_buffer[head + 1] == 0x00)
                            {
                                ESP_LOGI(TAG, "answer check 0x00");
                            }
                            else if (zw101_node.pack_buffer[head + 1] == 0x01)
                            {
                                ESP_LOGI(TAG, "answer check 0x01");
                            }
                            else if (zw101_node.pack_buffer[head + 1] == 0x05)
                            {
                                ESP_LOGI(TAG, "answer check 0x05");
                            }
                        }
                        else
                        {
                            zw101_ps_auto_flag = 1;
                        }
                    }
                    vTaskDelay(pdMS_TO_TICKS(100));
                }
                // 休眠模块
                my_zw101_ps_sleep(&zw101_node);
                while (xQueueReceive(xQueue, &node, (TickType_t)0) == pdTRUE)
                {
                    memcpy(zw101_node.pack_buffer, node.buffer, node.len);
                    zw101_node.pack_buffer_len = node.len;
                    uint16_t head, len;
                    if (my_zw101_answer_check(&zw101_node, &head, &len) == 0)
                    {
                        ESP_LOGI(TAG, "zw101 sleep...");
                    }
                    vTaskDelay(pdMS_TO_TICKS(100));
                }
                // 关闭电源
                ctrl_pin.status = 0;
                gpio_set_level(ctrl_pin.pin, ctrl_pin.status);
                // todo开启门或关闭门
                if (zw101_ps_auto_flag == 0)
                {
                    ESP_LOGI(TAG, "open door");
                }
                else
                {
                    ESP_LOGI(TAG, "not open door");
                }
            }
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
    vQueueDelete(xQueue);
}